package com.example.chamberlainserver.aspect;

import com.example.chamberlainserver.Entry.User;
import com.example.chamberlainserver.Service.UserLogService;
import com.example.chamberlainserver.security.JwtTokenUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;

/**
 * 日志切面，用于记录用户操作日志
 */
@Aspect
@Component
public class LogAspect {
    
    @Autowired
    private UserLogService userLogService;
    
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 定义切点：所有控制器方法
     */
    @Pointcut("execution(* com.example.chamberlainserver.controller.*.*(..))")
    public void controllerPointcut() {}
    
    /**
     * 环绕通知：记录操作日志
     */
    @Around("controllerPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = null;
        boolean status = true;
        String errorMsg = null;
        
        try {
            // 执行目标方法
            result = joinPoint.proceed();
            return result;
        } catch (Exception e) {
            status = false;
            errorMsg = e.getMessage();
            throw e;
        } finally {
            try {
                // 记录操作日志
                recordLog(joinPoint, startTime, status, errorMsg);
            } catch (Exception e) {
                // 记录日志时出现异常，不影响主流程
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 记录操作日志
     */
    private void recordLog(ProceedingJoinPoint joinPoint, long startTime, boolean status, String errorMsg) {
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        
        HttpServletRequest request = attributes.getRequest();
        
        // 获取当前用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication == null || !authentication.isAuthenticated() || "anonymousUser".equals(authentication.getPrincipal())) {
            return; // 未登录用户不记录日志
        }
        
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String username = userDetails.getUsername();
        int userId = 0;
        String userRole = null;
        
        // 从JWT令牌中获取用户ID和角色
        String token = extractToken(request);

        System.out.println("token >>> " + token);
        if (token != null) {
            // 使用getClaimFromToken方法获取自定义声明
            try {
                // 尝试从token中获取userId
                Object userIdObj = jwtTokenUtil.getClaimFromToken(token, claims -> claims.get("userId"));
                if (userIdObj != null) {
                    if (userIdObj instanceof Integer) {
                        userId = (Integer) userIdObj;
                    } else if (userIdObj instanceof Long) {
                        userId = ((Long) userIdObj).intValue();
                    } else if (userIdObj instanceof Number) {
                        userId = ((Number) userIdObj).intValue();
                    } else if (userIdObj instanceof String) {
                        try {
                            userId = Integer.parseInt((String) userIdObj);
                        } catch (NumberFormatException nfe) {
                            // 无法解析为Integer，记录错误并继续
                            System.err.println("无法将userId转换为Integer: " + userIdObj);
                        }
                    }
                }
                
                // 尝试从token中获取role
                Object roleObj = jwtTokenUtil.getClaimFromToken(token, claims -> claims.get("role"));

                if (roleObj != null) {
                    userRole = roleObj.toString();
                }
            } catch (Exception e) {
                // 如果token中没有这些信息，则忽略
                System.err.println("从token中提取信息时出错: " + e.getMessage());
                e.printStackTrace();
            }
        }
        
        // 如果无法从token中获取userId，则不记录日志
        if (userId == 0) {
            System.err.println("无法获取用户ID，跳过日志记录");
            return;
        }
        
        // 获取方法信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getDeclaringClass().getSimpleName() + "." + method.getName();
        
        // 获取请求参数
        String requestParams = getRequestParams(joinPoint);
        
        // 获取请求URL和方法
        String requestUrl = request.getRequestURI();
        String requestMethod = request.getMethod();
        
        // 获取请求IP
        String requestIp = getIpAddress(request);
        
        // 获取操作模块和类型
        String module = getModule(requestUrl);
        String operation = getOperation(requestMethod, method.getName());
        
        // 获取操作描述
        String description = getDescription(method.getName(), requestUrl);
        
        // 计算执行时长
        long duration = System.currentTimeMillis() - startTime;
        
        // 记录操作日志
        userLogService.recordUserAction(userId, username, userRole, module, operation, description, 
                requestMethod, requestUrl, requestIp, requestParams, status, errorMsg, duration);
    }
    
    /**
     * 从请求中提取JWT令牌
     */
    private String extractToken(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
    
    /**
     * 获取请求参数
     */
    private String getRequestParams(ProceedingJoinPoint joinPoint) {
        try {
            Object[] args = joinPoint.getArgs();
            if (args.length == 0) {
                return "";
            }
            return objectMapper.writeValueAsString(args);
        } catch (Exception e) {
            return "[无法解析的参数]";
        }
    }
    
    /**
     * 获取请求IP地址
     */
    private String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    
    /**
     * 根据URL获取操作模块
     */
    private String getModule(String url) {
        if (url.contains("/auth")) {
            return "认证管理";
        } else if (url.contains("/user")) {
            return "用户管理";
        } else if (url.contains("/material")) {
            return "物资管理";
        } else if (url.contains("/category")) {
            return "分类管理";
        } else if (url.contains("/location")) {
            return "位置管理";
        } else if (url.contains("/tripping")) {
            return "跳闸管理";
        } else if (url.contains("/dashboard")) {
            return "数据大屏";
        } else if (url.contains("/role")) {
            return "角色管理";
        } else {
            return "其他";
        }
    }
    
    /**
     * 根据请求方法和方法名获取操作类型
     */
    private String getOperation(String requestMethod, String methodName) {
        if ("GET".equals(requestMethod)) {
            if (methodName.startsWith("get") || methodName.startsWith("find") || methodName.startsWith("query") || methodName.startsWith("search")) {
                return "查询";
            } else {
                return "查看";
            }
        } else if ("POST".equals(requestMethod)) {
            if (methodName.startsWith("add") || methodName.startsWith("save") || methodName.startsWith("create") || methodName.startsWith("insert")) {
                return "新增";
            } else if (methodName.startsWith("login") || methodName.contains("Login")) {
                return "登录";
            } else if (methodName.startsWith("register") || methodName.contains("Register")) {
                return "注册";
            } else {
                return "提交";
            }
        } else if ("PUT".equals(requestMethod) || "PATCH".equals(requestMethod)) {
            return "更新";
        } else if ("DELETE".equals(requestMethod)) {
            return "删除";
        } else {
            return "其他";
        }
    }
    
    /**
     * 获取操作描述
     */
    private String getDescription(String methodName, String url) {
        StringBuilder desc = new StringBuilder();
        
        // 根据URL和方法名生成描述
        if (url.contains("/auth")) {
            if (methodName.contains("login")) {
                desc.append("用户登录");
            } else if (methodName.contains("register")) {
                desc.append("用户注册");
            } else {
                desc.append("认证操作");
            }
        } else if (url.contains("/user")) {
            desc.append("用户");
            if (methodName.startsWith("get") || methodName.startsWith("find") || methodName.startsWith("query")) {
                desc.append("查询");
            } else if (methodName.startsWith("add") || methodName.startsWith("save") || methodName.startsWith("create")) {
                desc.append("新增");
            } else if (methodName.startsWith("update") || methodName.startsWith("modify")) {
                desc.append("更新");
            } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
                desc.append("删除");
            } else {
                desc.append("操作");
            }
        } else if (url.contains("/material")) {
            desc.append("物资");
            if (methodName.startsWith("get") || methodName.startsWith("find") || methodName.startsWith("query")) {
                desc.append("查询");
            } else if (methodName.startsWith("add") || methodName.startsWith("save") || methodName.startsWith("create")) {
                desc.append("新增");
            } else if (methodName.startsWith("update") || methodName.startsWith("modify")) {
                desc.append("更新");
            } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
                desc.append("删除");
            } else {
                desc.append("操作");
            }
        } else if (url.contains("/dashboard")) {
            desc.append("查看数据大屏");
            if (url.contains("/system-overview")) {
                desc.append("系统概览");
            } else if (url.contains("/material-overview")) {
                desc.append("物资概览");
            } else if (url.contains("/user-activity")) {
                desc.append("用户活跃度");
            } else if (url.contains("/category-ratio")) {
                desc.append("物资分类占比");

            } else if (url.contains("/material-usage-ranking")) {
                desc.append("物资使用排行");
            } else if (url.contains("/low-stock-materials")) {
                desc.append("库存不足物资");
            } else if (url.contains("/tripping-stats")) {
                desc.append("跳闸统计");
            } else if (url.contains("/login-stats")) {
                desc.append("登录统计");
            } else if (url.contains("/operation-distribution")) {
                desc.append("操作分布");
            }
        } else {
            desc.append("其他操作");
        }
        
        return desc.toString();
    }
}